home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / BootX 1.2.2 / Sources / lib / MoreCFMPatches / MoreCFMPatches.c next >
Text File  |  2001-07-23  |  43KB  |  1,183 lines

  1. /*
  2.     File:        MoreCFMPatches.c
  3.  
  4.     Contains:    Implementation of CFM patching technology.
  5.  
  6.     Written by: Quinn
  7.  
  8.     Copyright:    Copyright ゥ 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.  
  20.          <1>     16/3/99    Quinn   First checked in.
  21. */
  22.  
  23. ////////////////////////////////////////////////////////////////
  24.  
  25. // MoreIsBetter Setup
  26.  
  27. #include "MoreSetup.h"
  28.  
  29. // Standard Mac OS Interfaces
  30.  
  31. #include <CodeFragments.h>
  32. #include <OSUtils.h>
  33. #include <stddef.h>
  34.  
  35. // MIB Interfaces
  36.  
  37. #include "MoreOSUtils.h"
  38.  
  39. // Our Prototypes
  40.  
  41. #include "MoreCFMPatches.h"
  42.  
  43. ////////////////////////////////////////////////////////////////
  44.  
  45. // We need to compile this code as CFM-PPC.  Why?  Because
  46. // we're statically linking in some PowerPC assembly language
  47. // and that only works when generating CFM-PPC.  We could have
  48. // an alternate technique to allow classic 68K code to patch
  49. // CFM entry points, but that seems like a too much work right now.
  50. // Also, I want to use CFM to get the MoreCFMPatchesLib to
  51. // allow us to be overridden by a system library.
  52.  
  53. #if !TARGET_CPU_PPC || !TARGET_RT_MAC_CFM
  54.     #error "MoreCFMPatches.c" will only compile for CFM-PPC.
  55. #endif
  56.  
  57. ////////////////////////////////////////////////////////////////
  58. #pragma mark ----- Diagrams -----
  59.  
  60. /*
  61.     Introduction
  62.     ------------
  63.     
  64.             IMPORTANT:
  65.             Before looking at this code, you need to read and under the
  66.             following:
  67.  
  68.                 a) "Mac OS Runtime Architectures" -- This Inside Macintosh-like
  69.                     book is available from <http://www.apple.com/developer/>.
  70.                     You should concentrate on the sections describing CFM 
  71.                     architectures, especially if terms like "TVector" make your
  72.                     eyes glaze over.
  73.  
  74.                 b) "MoreCFMPatches.h" -- The comments in the interface file for 
  75.                    this module contain information about its goal, as well as
  76.                    some important invariants for TVectors.
  77.  
  78.     The basic design feature of this module is the "patch island".  Each
  79.     patch island contains a list of patches that have been attached to 
  80.     a particular TVector, along with evil PowerPC assembly language that
  81.     glues the TVector to the patches.  The assembly language is particularly
  82.     evil because the patching mechanism must maintain the TVector invariants
  83.     described in "MoreCFMPatches.h".  It is described in very great detail
  84.     in the "MoreCFMPatching.s" file.
  85.     
  86.     A key detail of the assembly language is that the code contains two entry
  87.     points.  When a client calls the patched TVector, it actually branches to
  88.     "patchIslandEntry", which is responsible for routing the patch through the 
  89.     patch chain.  When a patch wishes to call through to the next patch in the
  90.     chain, it calls gMoreCFMPatchesCallThrough, which calls the "callThrough"
  91.     entry point of the assembly language to do the appropriate skank.
  92.     Both entry points actually share a significant proportion of their code.
  93.     
  94.     A patch island contains a fixed size header which is mostly
  95.     PowerPC instructions (there's also a signature which we use to identify
  96.     the patch island format), followed by an unbounded array of "patch records".
  97.     Each patch record describes one particular patch on the TVector,
  98.     except the last patch record, which describes the original TVector itself.
  99.  
  100.     Patches in the patch record are executed in order; when a client calls
  101.     the original TVector, the first patch record is executed.  It has the
  102.     choice of calling through to the next patch record or simply returning
  103.     to the caller.  Under this architecture, all patches are 'surround'
  104.     patches.  There is no specific provision for 'head' or 'tail' patches,
  105.     although each is a degenerate case of the surround patch.
  106.     
  107.     The assembly code in the patch island must be able to reference the
  108.     patch records in the patch island.  This is particularly tricky because
  109.     PowerPC has no "PC-relative" addressing modes.  Instead, we load up
  110.     the address of the patch records using immediate instructions.  When
  111.     we construct the patch island, we modify these instructions "on the fly"
  112.     to contain the right pointer.  This allows us to store an arbitrary
  113.     32-bit variable inside the patch island itself, which can be accessed from
  114.     both C and assembly.  This 32-bit variable is known as the patch island
  115.     "payload".
  116.  
  117.     As you can imagine, there is a very incestuous relationship between
  118.     the C and assembly language code in this module.  If you make any
  119.     changes to the C data structures PatchIsland and PatchRecord, you will
  120.     have to make corresponding changes to the assembly language.  Similarly,
  121.     if you make any changes to the assembly language, even adding or
  122.     removing an instruction, you will have to change the C data structures.
  123.     
  124.             IMPORTANT:
  125.             If you make any significant changes to the way this code
  126.             works, you *MUST* change the signature in the patch island.
  127.             Otherwise other developers who use this code will start
  128.             assuming that your patches are the same format as their
  129.             patches, with tragic results.
  130.  
  131.     The patch island concept was designed by various folks in Apple's
  132.     tool group during the Copland effort.  It was explained to me in
  133.     minute detail by Alan Lillich (thanks Alan!).  However, this code
  134.     is entirely my work and all errors are therefore mine.
  135.     
  136.     
  137.     Patch Island Structure in Memory
  138.     --------------------------------
  139.  
  140.     This diagram shows how a patch island might look in memory.
  141.     [Low memory is shown at the top of the page in typically confusing
  142.     computer geek style.]  The patch starts with the patch island
  143.     assembly language code, which is followed by an unbounded array
  144.     of patch records.
  145.     
  146.     Each patch record contains a pointer to the code that actually
  147.     implements the patch and a pointer to the TVector for that code.
  148.     The distinction is important.  Specifically, the address of the
  149.     original TVector is necessary so that a) we can update all
  150.     the patched TVectors when we move the patch island, and b) we
  151.     can unpatch a patch TVector's code pointer when the remove
  152.     the patch from the chain.
  153.         
  154.                     +-------------------+
  155.                     | Patch Island code |
  156.                     |                    |
  157.                     |                    |
  158.                     |                    |
  159.                     +-------------------+
  160.         patches[0]    | patchCode            |    <- most recent patch
  161.                     | patchTVector        |
  162.                     +-------------------+
  163.         patches[1]    | patchCode            |
  164.                     | patchTVector        |
  165.                     +-------------------+
  166.                     .                    .
  167.                     .                    .
  168.                     .                    .
  169.                     +-------------------+
  170.         patches[N]    | patchCode            |    <- original implementation
  171.                     | patchTVector        |
  172.                     +-------------------+
  173.  
  174.     Before and After Patching
  175.     -------------------------
  176.     
  177.     The following diagram shows the state of the machine before
  178.     MyPatch is applied to NavLoad.  Each TVector contains a pointer
  179.     to its own code and TOC.  
  180.                 
  181.         NavLoad ->    +--------------------+
  182.                     | NavLoad code ->     |
  183.                     | NavLoad TOC  ->     |
  184.                     +--------------------+
  185.         
  186.         MyPatch ->    +--------------------+
  187.                     | MyPatch code ->     |
  188.                     | MyPatch TOC  ->     |
  189.                     +--------------------+
  190.     
  191.     The following diagram shows what happens after you execute the
  192.     code:
  193.     
  194.         err = MorePatchTVector(NavLoad, MyPatch);
  195.     
  196.     Note that the code pointers for *both* TVectors have been changed
  197.     to point to patchIslandEntry.  From now on, if either of these
  198.     TVectors is called, the patch will execute.  In addition, if
  199.     MyPatch calls gMoreCFMPatchesCallThrough, it will enter the patch
  200.     island at callThrough, which routes the call to the next patch in
  201.     the patch island.
  202.     
  203.     This organisation generalises to more than one patch.  Trust me (-:
  204.     
  205.         NavLoad ->    +--------------------+
  206.                     | patchIslandEntry ->|
  207.                     | NavLoad TOC  ->     |
  208.                     +--------------------+
  209.         
  210.         MyPatch ->    +--------------------+
  211.                     | patchIslandEntry ->|
  212.                     | MyPatch TOC  ->     |
  213.                     +--------------------+
  214.  
  215.      PatchIsland -> +--------------------+
  216.                     | callThrough         |
  217. patchIslandEntry -> | patchIslandEntry     | (loads r11 with address of patches[0])
  218.                     | patchIslandCommon     |
  219.                     +--------------------+
  220.                     | MyPatch code ->     | patches[0]
  221.                     | MyPatch ->         | (ie address of the TVector)
  222.                     +--------------------+
  223.                     | NavLoad code ->     | patches[1]
  224.                     | NavLoad ->         | (ie address of the TVector)
  225.                     +--------------------+
  226.  
  227.     Stack Diagrams
  228.     --------------
  229.  
  230.     The key to this design is the use of a "system reserved" word
  231.     in the PowerPC stack frame.  This word is 16 bytes above the
  232.     stack pointer and is officially designated as reserved for system
  233.     use.  This sample serves to document the Apple official use of this
  234.     word.
  235.     
  236.     The two diagrams below show how a stack frame is built when
  237.     a patch is in place.  The caller calls the NavLoad TVector,
  238.     which actually runs the patchIslandEntry code in our patch island.
  239.     This code gets the address of the first patch record from
  240.     the patch island's payload.  It stores that address in the
  241.     *caller's* frame, and then proceeds to call through to MyPatch.
  242.     When MyPatch calls gMoreCFMPatchesCallThrough (which is routed
  243.     through to the callThrough entry point of the patch island),
  244.     the assembly language grabs the pointer to the current patch
  245.     record from the caller's stack (that's the original caller, not
  246.     MyPatch -- it can find it by looking up one stack frame, hence
  247.     the restriction that you can only call gMoreCFMPatchesCallThrough
  248.     from the mainline of your patch), increments it to point to
  249.     the next patch record, stores it in the current frame (ie
  250.     MyPatch's frame) and calls through to the next patch.
  251.     
  252.     Eventually this process reaches the last patch record in the
  253.     patch chain, which contains the code pointer for the original
  254.     implementation.  At this point, the most recent patch record 
  255.     pointer stored in a frame points to the last patch record in
  256.     the chain.  This is cool though, because the original implementation
  257.     is never going to call gMoreCFMPatchesCallThrough, and hence
  258.     we never increment the current patch record pointer off the end
  259.     of the patch chain.
  260.     
  261.         Caller's stack frame before calling NavLoad.
  262.             
  263.                     | Caller             |     ^
  264.                     |                     |     |
  265.                     |                     |     |
  266.                     |                     |     | link to previous frame
  267.              sp ->    |                     | --+
  268.                     +--------------------+
  269.  
  270.         MyPatch's stack frame
  271.         
  272.                     | Caller             |     ^
  273.                     |                     |     |
  274.          sp^+16 ->    | &patches[0]         |     |
  275.                     |                     |     | link to previous frame
  276.             sp^ ->    |                     | --+
  277.                     +--------------------+     |
  278.                     | MyPatch             |     |
  279.                     |                     |     |
  280.                     |                     |     |
  281.                     |                     |     | link to previous frame
  282.              sp ->    |                     | --+
  283.                     +--------------------+
  284.     
  285.         So MyPatch can figure out what the next patch to call
  286.         is by looking up one stack frame to the Caller's stack
  287.         frame and then extracting the pointer to the current
  288.         PatchRecord from offset 16 into the frame and then
  289.         incrementing that pointer by kPatchRecordSize.
  290.         
  291.         NavLoad's stack frame
  292.         
  293.                     | Caller             |     ^
  294.                     |                     |     |
  295.         sp^^+16 ->    | &patches[0]         |     |
  296.                     |                     |     | link to previous frame
  297.            sp^^ ->    |                     | --+
  298.                     +--------------------+     |
  299.                     | MyPatch             |     |
  300.                     |                     |     |
  301.          sp^+16 ->    | &patches[1]         |     |
  302.                     |                     |     | link to previous frame
  303.             sp^ ->    |                     | --+
  304.                     +--------------------+     |
  305.                     | NavLoad             |     |
  306.                     |                     |     |
  307.                     |                     |     |
  308.                     |                     |     | link to previous frame
  309.              sp ->    |                     | --+
  310.                     +--------------------+
  311.  
  312.         If NavLoad attempted to call through to the next patch,
  313.         it would fail because we've reached the end of the patch
  314.         array.    However, NavLoad is the original (non-patched)
  315.         routine, so it shouldn't try to call through.
  316.  
  317.     Why?
  318.     ----
  319.     
  320.     So, why do we use this convoluted approach?  Well, the most
  321.     obvious answer is "because it works".  However, I doubt this
  322.     will satisfy you.
  323.     
  324.     Patching CFM is extremely tricky.  The biggest problem is one
  325.     of data storage.  CFM fragments can be multiply instantiated,
  326.     with each fragment having its own data section, and hence its
  327.     own TVectors.  Each instance of the TVector's may have a
  328.     different patch chain.  [For example, all instances may have
  329.     some global patches but an application might apply its own
  330.     per-context patches.]  So you can't just store the information
  331.     about the patches in a global variable.  It has to be stored
  332.     per-TVector.
  333.     
  334.     Which implies that the TVector has to somehow reference this
  335.     storage.  I'm not sure whether you've noticed, but TVectors
  336.     don't have a lot of extra space for system expansion.  In fact,
  337.     the only field that's guaranteed to exist is the first field,
  338.     ie the pointer to the code.  So we have to use that field
  339.     to point to our patching code, and construct the patching code
  340.     so that it can find the information about what patches to
  341.     apply to this particular TVector, preferably without an expensive
  342.     table lookup.
  343.     
  344.     The above pretty much dictates the use of PC-relative storage,
  345.     which in turn implies that we duplicate some patch code
  346.     for each patch.  [Actually, we could share more of the patch
  347.     code than we do, but the complexity of doing this seems
  348.     to outweigh the memory savings.]  The rest of the design falls
  349.     out from there.
  350.  
  351. */
  352.  
  353. ////////////////////////////////////////////////////////////////
  354. #pragma mark ---- Patch Island Data Structures -----
  355.  
  356. // We align this with mac68k alignment because a) all the structures
  357. // are padded such that mac68k is optimal for PowerPC as well, and
  358. // b) we need to guarantee a *specific* alignment in memory, so we might
  359. // as well choose a well supported one.
  360.  
  361. #pragma options align=mac68k
  362.  
  363. // A PatchRecord is used to hold details about a patch
  364. // in the patch island.     The details include a pointer
  365. // to the code of the routine and a pointer to the routine's
  366. // transition vector, along with a creator (for debugging
  367. // and patch management) and a refcon (for the patch owner's
  368. // use).
  369.  
  370. struct PatchRecord {
  371.     void    *patchCode;
  372.     TVector *patchTVector;
  373.     OSType    patchCreator;
  374.     void    *patchRefcon;
  375. };
  376. typedef struct PatchRecord PatchRecord;
  377.  
  378. // The PatchIsland structure represents the (assembly language) code of
  379. // the patch and an unbounded array of PatchRecords that presents the
  380. // patches applied (the last entry represents the original routine before
  381. // patching).
  382. //
  383. // For details on this structure, see "MoreCFMPatches.s", which describes
  384. // the actual assembly language.  You shouldn't change this structure
  385. // unless you also change that code.  If you change either, you should
  386. // also change the kPatchIslandSignature, which allows us to identify
  387. // our specific patching technology.
  388.  
  389. struct PatchIsland {
  390.     UInt32 callThrough[4];
  391.     OSType signature;
  392.     UInt16 patchIslandEntry[4];
  393.     UInt32 patchIslandCommon[6];
  394.     PatchRecord patches[1];
  395. };
  396. typedef struct PatchIsland PatchIsland;
  397.  
  398. enum {
  399.     kPatchIslandHeaderSize = offsetof(PatchIsland, patches)
  400. };
  401.  
  402. #pragma options align=reset
  403.  
  404. ////////////////////////////////////////////////////////////////
  405. #pragma mark ----- Shared with "MoreCFMPatches.s" -----
  406.  
  407. // Constants shared with "MoreCFMPatches.s".  If you change them
  408. // here, you must also change them there.
  409.  
  410. enum {
  411.  
  412.     // When calling a patch, we store a pointer to the current
  413.     // PatchRecord in a "reserved for system use" field of the frame
  414.     // of the caller.
  415.     // This allows our "call through" glue to find the next patch to
  416.     // call (or the original routine, which is the last PatchRecord
  417.     // in the array).  See the stack diagrams for details.
  418.     //
  419.     // For more information about the system reserved frame offset,
  420.     // see the "Mac OS Runtime Architectures", available from
  421.     // <http://www.apple.com/developer/>.
  422.     
  423.     kSystemReservedFrameOffset = 16,
  424.     
  425.     // Patch islands installed by this module contain a signature to
  426.     // help us identify whether we have patched a TVector.    If you
  427.     // modify this code to implement another patching mechanism that
  428.     // is not 100% compatible with this one, you must change this
  429.     // signature to avoid confusion.
  430.  
  431.     kPatchIslandSignature = 'Nat!',
  432.  
  433.     // This is sizeof(PatchRecord).     We define it as a strict constant
  434.     // so as to be in sync with the assembly language code.     Before
  435.     // running (see below) we also:
  436.     //
  437.     //     MoreAssertQ(kPatchRecordSize == sizeof(PatchRecord));
  438.         
  439.     kPatchRecordSize = 16
  440. };
  441.  
  442. ////////////////////////////////////////////////////////////////
  443. #pragma mark ----- Patch Island Primitives -----
  444.  
  445. // Much of the code here contains intimate details of the assembly
  446. // code in "PatchManager.s"
  447.  
  448. // This declaration allows us to access the assembly language code
  449. // for the patch island.  It's declared to return a long so that
  450. // it's type compatible with ProcPtr, which is how it's exported
  451. // to clients.  In truth, there's no way you can look at this code
  452. // as a C function, so there's no good prototype for it.
  453.  
  454. extern long MoreCFMPatchesCallThrough(void);
  455.  
  456. // The following declarations contain information about the assembly
  457. // language code in the patch island, specifically the patchIslandEntry
  458. // field which is the code we modify to include the payload.
  459.  
  460. enum {
  461.     kEntryOpcode0 = 0x3D60,
  462.     kEntryOpcode1 = 0x616B,
  463.     
  464.     kEntryOpcode0Index = 0,
  465.     kEntryHighPayloadIndex = 1,
  466.     kEntryOpcode1Index = 2,
  467.     kEntryLowPayloadIndex = 3
  468. };
  469.  
  470. static UInt32 GetPatchIslandPayload(PatchIsland *patchIsland)
  471.     // This routine gets the payload within the patch island.
  472.     // The 32 bit instructions containing the payload are
  473.     // each represented by two UInt16s.     The second UInt16 in the
  474.     // the instruction is the data portion of the instruction.
  475.     // The first instruction (a "lis") contains the high 16 bits
  476.     // of the payload, and the second (an "ori") contains the 
  477.     // low 16 bits.
  478. {
  479.     MoreAssertQ(patchIsland != nil);
  480.     MoreAssertQ(patchIsland->signature == kPatchIslandSignature);
  481.     MoreAssertQ(patchIsland->patchIslandEntry[kEntryOpcode0Index] == kEntryOpcode0);
  482.     MoreAssertQ(patchIsland->patchIslandEntry[kEntryOpcode1Index] == kEntryOpcode1);
  483.     
  484.     return     (patchIsland->patchIslandEntry[kEntryHighPayloadIndex] << 16)
  485.            | patchIsland->patchIslandEntry[kEntryLowPayloadIndex];
  486. }
  487.  
  488. static void SetPatchIslandPayload(PatchIsland *patchIsland,
  489.                                   UInt32 newPayload)
  490.     // This routine sets the payload of a patch island.     The storage
  491.     // for the payload is described in the routine above.  The only
  492.     // tricky part is that it has to call MakeDataExecutable to ensure
  493.     // that the code modification "sticks".
  494.     //
  495.     // It's important that this flush the code cache for the entire
  496.     // patch island header, not just the two instructions that it modifies.
  497.     // This is because other routines rely on this to flush the entire
  498.     // header.
  499. {
  500.     MoreAssertQ(patchIsland != nil);
  501.     MoreAssertQ(patchIsland->signature == kPatchIslandSignature);
  502.     MoreAssertQ(patchIsland->patchIslandEntry[kEntryOpcode0Index] == kEntryOpcode0);
  503.     MoreAssertQ(patchIsland->patchIslandEntry[kEntryOpcode1Index] == kEntryOpcode1);
  504.  
  505.     patchIsland->patchIslandEntry[kEntryHighPayloadIndex] =
  506.                                                 (newPayload >> 16);
  507.     patchIsland->patchIslandEntry[kEntryLowPayloadIndex] =
  508.                                                  newPayload;
  509.     MakeDataExecutable(patchIsland, kPatchIslandHeaderSize);
  510. }
  511.  
  512. static Boolean ValidPatchIsland(PatchIsland *patchIsland)
  513.     // This routine returns true if patchIsland looks
  514.     // like a valid patch island.  In the non-debug build,
  515.     // it's used by HasTVectorBeenPatched to determine whether
  516.     // there's a patch island already in place for a particular
  517.     // TVector.  In debug builds, it's used in assertions everywhere.
  518.     //
  519.     // The specific checks include:
  520.     //
  521.     // o does the patch island contain our signature
  522.     // o does the patch island start with our two instructions,
  523.     //   ie "lis" and "ori"
  524.     // o do those instructions create a constant that points
  525.     //     to the patches field of the PatchIsland structure.
  526.     //
  527.     // This routine could be more robust.  Specifically, it could
  528.     // check that all the codePointers of all the patchTVectors of
  529.     // all the PatchRecords point to this patch island.  However,
  530.     // that's more work than I'm prepared to do right now.
  531. {
  532.     return (patchIsland != nil)
  533.         && (patchIsland->signature == kPatchIslandSignature) 
  534.         && (patchIsland->patchIslandEntry[kEntryOpcode0Index] == kEntryOpcode0)
  535.         && (patchIsland->patchIslandEntry[kEntryOpcode1Index] == kEntryOpcode1)
  536.         && GetPatchIslandPayload(patchIsland) == (UInt32) &patchIsland->patches[0];
  537. }
  538.  
  539. static PatchIsland *GetPatchIslandFromTVector(TVector *tVector)
  540.     // If tVector points to a TVector that has been patched,
  541.     // this routine returns a pointed to the patch island by
  542.     // simply subtracting a constant.
  543. {
  544.     MoreAssertQ(tVector != nil);
  545.  
  546.     return (PatchIsland *) ( (char *)(tVector->codePointer) - 
  547.                              offsetof(PatchIsland, patchIslandEntry)
  548.                            );
  549. }
  550.  
  551. static Boolean HasTVectorBeenPatched(TVector *tVector)
  552.     // This routine determines whether tVector has been patched by
  553.     // us.    It does this working out where the patch island would be
  554.     // (if there was one) and then looking for various specific features
  555.     // of a patch island, namely those checked by ValidPatchIsland.
  556.     //
  557.     // Later on in the code, we use this routine to decide whether we
  558.     // should create a new patch island for the TVector or simply
  559.     // add ourselves to the front of the existing patch island.
  560. {
  561.     Boolean result;
  562.     PatchIsland *potentialPatchIsland;
  563.  
  564.     result = false;
  565.     if (tVector != nil) {
  566.         potentialPatchIsland = GetPatchIslandFromTVector(tVector);
  567.     
  568.         result = ValidPatchIsland(potentialPatchIsland);
  569.     }
  570.     return result;    
  571. }
  572.  
  573. static OSStatus GetPatchIslandPatchCount(PatchIsland *patchIsland, ItemCount *patchCount)
  574.     // This routine calculates the number of PatchRecords in a patch
  575.     // island (including the last PatchRecord that represents the
  576.     // original routine that was patched).    It determines this using the
  577.     // the size of the pointer block that contains the patch island.
  578.     //
  579.     // I decided against storing the count of the number of patches
  580.     // in the patch island because there's a reliable way to get
  581.     // the size of Memory Manager pointer blocks and adding a count
  582.     // would just be adding redundant information that I'd have to keep
  583.     // in sync.
  584. {
  585.     OSStatus err;
  586.     Size patchIslandSize;
  587.     
  588.     MoreAssertQ(ValidPatchIsland(patchIsland));
  589.     MoreAssertQ(patchCount    != nil);
  590.  
  591.     patchIslandSize = GetPtrSize( (Ptr) patchIsland );
  592.     err = MemError();
  593.     if (err == noErr) {
  594.         *patchCount = ( patchIslandSize - kPatchIslandHeaderSize ) / sizeof(PatchRecord);
  595.         MoreAssertQ(*patchCount * sizeof(PatchRecord) + kPatchIslandHeaderSize == patchIslandSize);
  596.     }
  597.     return err;
  598. }
  599.  
  600. static OSStatus FindPatchInPatchIsland(PatchIsland *patchIsland, TVector *tVector, ItemCount *patchIndex)
  601.     // This routine determines whether a TVector has been patched with
  602.     // this a patch island.     It does this by searching through the list
  603.     // of PatchRecords in the patch island, looking for the TVector.
  604.     // If it finds it, it returns the index to the PatchRecord in
  605.     // patchIndex.
  606. {
  607.     OSStatus  err;
  608.     ItemCount i;
  609.     ItemCount patchCount;
  610.     
  611.     MoreAssertQ(ValidPatchIsland(patchIsland));
  612.     MoreAssertQ(tVector        != nil);
  613.     MoreAssertQ(patchIndex    != nil);
  614.  
  615.     err = GetPatchIslandPatchCount(patchIsland, &patchCount);
  616.     if (err == noErr) {
  617.         err = kPatchNotFoundInPatchIslandErr;
  618.         for (i = 0; i < patchCount; i++) {
  619.             if ( patchIsland->patches[i].patchTVector == tVector ) {
  620.                 *patchIndex = i;
  621.                 err = noErr;
  622.                 break;
  623.             }
  624.         }
  625.     }
  626.     
  627.     return err;
  628. }
  629.  
  630. static void SyncPatchedTVectors(PatchIsland *patchIsland, ItemCount patchCount)
  631.     // This routine sychronises a patch island with all TVectors that
  632.     // make up the patches.     It's used when we add or remove a patch
  633.     // to/from a patch island.    In this case, the patch island moves
  634.     // in memory.  So we have to go through the list of PatchRecords
  635.     // in the island, making sure that all the codePointer fields in
  636.     // all the transition vectors they point to point to the new
  637.     // patch island's entry point.
  638.     //
  639.     // We do this with interrupts disabled because I've been
  640.     // unable to prove to my satisfaction that everything works OK
  641.     // with interrupts enabled, even if you did rework the code
  642.     // to modify the TVectors in revese.  It's better to be safe
  643.     // than sorry.
  644.     //
  645.     // ・・・ Disabling interrupts in not going to be enough if the TVector
  646.     // is being used by MP threads. ・・・
  647. {
  648.     UInt16 oldLevel;
  649.     ItemCount i;
  650.  
  651.     MoreAssertQ(ValidPatchIsland(patchIsland));
  652.     MoreAssertQ(patchCount    >= 1);
  653.  
  654.     oldLevel = SetInterruptMask(7);
  655.     
  656.     for (i = 0; i < patchCount; i++) {
  657.         patchIsland->patches[i].patchTVector->codePointer = &patchIsland->patchIslandEntry[0];
  658.     }
  659.  
  660.     (void) SetInterruptMask(oldLevel);
  661. }
  662.  
  663. ////////////////////////////////////////////////////////////////
  664. #pragma mark ----- Memory Allocators -----
  665.  
  666. // Patch islands must be allocated in memory with the following
  667. // characteristics:
  668. //
  669. // 1. shared between all contexts that can access the TVector,
  670. // 2. persistent until the last context that can access the TVector
  671. //      goes away,
  672. // 3. held resident (if the TVector can be called when paging is unsafe).
  673. //
  674. // At the moment, the system heap fulfills all these requirements.
  675. // If you change the memory allocator to some other scheme, make sure it
  676. // still fulfills these requirements.
  677.  
  678. static OSStatus NewPatchIsland(ItemCount patchCount, PatchIsland **patchIsland)
  679. {
  680.     OSStatus err;
  681.     
  682.     MoreAssertQ(patchCount    >= 1);
  683.     MoreAssertQ(patchIsland != nil);
  684.  
  685.     err = noErr;
  686.     *patchIsland = (PatchIsland *) NewPtrSys( kPatchIslandHeaderSize + patchCount * sizeof(PatchRecord) );
  687.     if (*patchIsland == nil) {
  688.         err = MemError();
  689.         MoreAssertQ(err != noErr);
  690.     }
  691.     return err;
  692. }
  693.  
  694. static void DisposePatchIsland(PatchIsland *patchIsland)
  695. {
  696.     MoreAssertQ(patchIsland != nil);
  697.  
  698.     DisposePtr( (Ptr) patchIsland );
  699.     MoreAssertQ(MemError() == noErr);
  700. }
  701.  
  702. ////////////////////////////////////////////////////////////////
  703. #pragma mark ----- Patch Creation -----
  704.  
  705. static OSStatus CreateNewPatchIsland(TVector *tVectorToPatch)
  706.     // This routine creates a new patch island and applies it into
  707.     // tVectorToPatch.    The patch island contains one PatchRecord,
  708.     // which represents just the original routine that was patched.
  709. {
  710.     OSStatus err;
  711.     PatchIsland *newPatchIsland;
  712.     
  713.     MoreAssertQ(tVectorToPatch != nil);
  714.  
  715.     MoreAssertQ( ! HasTVectorBeenPatched(tVectorToPatch) );
  716.  
  717.     // Create the memory for the patch island in the system heap.
  718.         
  719.     err = NewPatchIsland(1, &newPatchIsland);
  720.     
  721.     // Fill out the patch island, first by cloning the standard patch
  722.     // island code, then by setting the payload (which also flushes
  723.     // the caches), then by filling out the first PatchRecord.
  724.     
  725.     if (err == noErr) {
  726.     
  727.         // OK, I'll admit, the first parameter to this BlockMoveData is pretty
  728.         // scary.  Basically MoreCFMPatchesCallThrough is a procedure pointer, ie
  729.         // a pointer to a TVector.    But we don't want to copy the TVector,
  730.         // we actually want to copy the code associated with it.  So we
  731.         // cast it to a TVector, extract the codePointer field and copy from
  732.         // that.
  733.         
  734.         BlockMoveData(    ((TVector *) MoreCFMPatchesCallThrough)->codePointer, 
  735.                         newPatchIsland, 
  736.                         sizeof(PatchIsland));
  737.         
  738.         SetPatchIslandPayload(newPatchIsland, (UInt32) &newPatchIsland->patches[0]);
  739.         newPatchIsland->patches[0].patchCode    = tVectorToPatch->codePointer;
  740.         newPatchIsland->patches[0].patchTVector = tVectorToPatch;
  741.         newPatchIsland->patches[0].patchCreator = 'last';
  742.         newPatchIsland->patches[0].patchRefcon    = nil;
  743.  
  744.         // The last thing we do is smash the code pointer for
  745.         // tVectorToPatch.    Because we do this with a single store, we
  746.         // don't need to disable interrupts.
  747.         
  748.         tVectorToPatch->codePointer = &newPatchIsland->patchIslandEntry[0];
  749.     }
  750.     
  751.     return err;
  752. }
  753.  
  754. static OSStatus AddPatchToPatchIsland(PatchIsland *existingPatchIsland,
  755.                                       TVector *patchTVectorToAdd,
  756.                                       OSType  creator,
  757.                                       void      *refcon)
  758.     // This routine adds a new patch to the front of the list of
  759.     // patches in existingPatchIsland.    The basic strategy is to
  760.     // create a new, bigger, pointer block in the system heap, and
  761.     // then move all the stuff out of the old patch island into the
  762.     // new one, and then switch the patched TVector's to point to
  763.     // the new patch island.
  764. {
  765.     OSStatus err;
  766.     ItemCount existingPatchCount;
  767.     PatchIsland *newPatchIsland;
  768.  
  769.     MoreAssertQ(ValidPatchIsland(existingPatchIsland));
  770.     MoreAssertQ(patchTVectorToAdd    != nil);
  771.     
  772.     // Create a new, bigger patch island in the system heap.
  773.     
  774.     err = GetPatchIslandPatchCount(existingPatchIsland, &existingPatchCount);
  775.     if (err == noErr) {
  776.         err = NewPatchIsland(existingPatchCount + 1, &newPatchIsland);
  777.     }
  778.     
  779.     // Fill out the new patch island with stuff from the old one.  First
  780.     // copy across the code and re-setup the payload (which also flushes
  781.     // the code cache).     Then copy across all the PatchRecords from the
  782.     // old patch island.  Then fill out the extra PatchRecord (ie
  783.     // patches[0]).     Then switch all the patched TVectors to point
  784.     // to the new patch island.
  785.     
  786.     if (err == noErr) {
  787.         
  788.         // The order here is important.     SetPatchIslandPayload flushes
  789.         // the code cache, so we must do it after we're done modifying
  790.         // the code.
  791.         
  792.         BlockMoveData(existingPatchIsland, newPatchIsland, kPatchIslandHeaderSize);
  793.         SetPatchIslandPayload(newPatchIsland, (UInt32) &newPatchIsland->patches[0]);
  794.         
  795.         BlockMoveData(&existingPatchIsland->patches[0], &newPatchIsland->patches[1], existingPatchCount * sizeof(PatchRecord));
  796.  
  797.         newPatchIsland->patches[0].patchCode    = patchTVectorToAdd->codePointer;
  798.         newPatchIsland->patches[0].patchTVector = patchTVectorToAdd;
  799.         newPatchIsland->patches[0].patchCreator = creator;
  800.         newPatchIsland->patches[0].patchRefcon  = refcon;
  801.         
  802.         SyncPatchedTVectors(newPatchIsland, existingPatchCount + 1);
  803.  
  804.         MoreAssertQ(ValidPatchIsland(newPatchIsland));
  805.  
  806.         // Now that every is switched over, dispose of the old
  807.         // patch island.
  808.         
  809.         DisposePatchIsland(existingPatchIsland);
  810.     }
  811.     
  812.     return err;
  813. }
  814.  
  815. ////////////////////////////////////////////////////////////////
  816. #pragma mark ----- Patch Destruction -----
  817.  
  818. static void DestroyPatchIsland(PatchIsland *patchIsland)
  819.     // This routine destroys a patch island by removing the last patch
  820.     // and disposing of the memory for the patch island.  It
  821.     // assumes that the patch island doesn't contain any real patches,
  822.     // ie there's only one PatchRecord in the patch island, which
  823.     // is the original routine.
  824. {
  825.     ItemCount patchCount;
  826.  
  827.     MoreAssertQ(ValidPatchIsland(patchIsland));
  828.     
  829.     MoreAssertQ( (GetPatchIslandPatchCount(patchIsland, &patchCount) == noErr) && (patchCount == 1) );
  830.  
  831.     // Restore the original TVector's code pointer.     Because we do this 
  832.     // with a single store, we don't need to disable interrupts.
  833.  
  834.     patchIsland->patches[0].patchTVector->codePointer = patchIsland->patches[0].patchCode;
  835.  
  836.     // Dispose of the patch island itself.
  837.  
  838.     DisposePatchIsland(patchIsland);
  839. }
  840.  
  841. static OSStatus RemovePatchFromPatchIsland(PatchIsland *existingPatchIsland, ItemCount patchIndex)
  842.     // This routine removes the patch (specified by patchIndex, an index
  843.     // into the patches array of PatchRecords) from the patch island.
  844.     // It does this by creating a new patch island without the patch
  845.     // and switching the patch to use the new patch island.
  846. {
  847.     OSStatus err;
  848.     ItemCount existingPatchCount;
  849.     PatchIsland *newPatchIsland;
  850.     
  851.     MoreAssertQ(ValidPatchIsland(existingPatchIsland));
  852.     MoreAssertQ(patchIndex >= 0);
  853.  
  854.     // Create a new, smaller patch island in the system heap.
  855.  
  856.     err = GetPatchIslandPatchCount(existingPatchIsland, &existingPatchCount);
  857.     if (err == noErr) {
  858.         MoreAssertQ(patchIndex < existingPatchCount);
  859.         err = NewPatchIsland(existingPatchCount - 1, &newPatchIsland);
  860.     }
  861.  
  862.     // Fill out the new patch island with stuff from the old one.  First
  863.     // copy across the code and re-setup the payload (which also flushes
  864.     // the code cache).     Then copy across all the PatchRecords from the
  865.     // old patch island.  Then switch all the patched TVectors to point
  866.     // to the new patch island.     Finally, unpatch the recently removed
  867.     // patch's TVector and destroy the existing patch island.
  868.     
  869.     // You might think I could use SetPtrSize here, but I can't.  This is
  870.     // because the patched TVector might be being called at interrupt time,
  871.     // so I have to atomically swap one valid patch island for another.
  872.     // I do this by disabling interrupts for the minimum amount of time,
  873.     // just inside SyncPatchedVectors.  I don't want to be calling
  874.     // SetPtrSize with interrupts disabled.
  875.  
  876.     if (err == noErr) {
  877.  
  878.         // The order here is important.     SetPatchIslandPayload flushes
  879.         // the code cache, so we must do it after we're done modifying
  880.         // the code.
  881.  
  882.         BlockMoveData(existingPatchIsland, newPatchIsland, kPatchIslandHeaderSize);
  883.         SetPatchIslandPayload(newPatchIsland, (UInt32) &newPatchIsland->patches[0]);
  884.         
  885.         // Copy across the PatchRecords, first the ones below patchIndex,
  886.         // then the ones above it.
  887.         
  888.         BlockMoveData(&existingPatchIsland->patches[0], &newPatchIsland->patches[0], patchIndex * sizeof(PatchRecord));
  889.         BlockMoveData(&existingPatchIsland->patches[patchIndex + 1], &newPatchIsland->patches[patchIndex], (existingPatchCount - (patchIndex + 1)) * sizeof(PatchRecord));
  890.  
  891.         // The order here is also important.  Make sure we completely
  892.         // switch over to using newPatchIsland before restoring
  893.         // the codePointer for the removed patch.
  894.  
  895.         SyncPatchedTVectors(newPatchIsland, existingPatchCount - 1);
  896.  
  897.         MoreAssertQ(ValidPatchIsland(existingPatchIsland));
  898.         
  899.         existingPatchIsland->patches[patchIndex].patchTVector->codePointer = existingPatchIsland->patches[patchIndex].patchCode;
  900.         DisposePatchIsland(existingPatchIsland);
  901.     }
  902.     
  903.     return err;
  904. }
  905.  
  906. ////////////////////////////////////////////////////////////////
  907. #pragma mark ----- Static Implementation -----
  908.  
  909. extern ProcPtr gMoreCFMPatchesCallThrough = MoreCFMPatchesCallThrough;
  910.     // I could have chosen to export MoreCFMPatchesCallThrough as
  911.     // a routine rather than a ProcPtr -- it would work just as
  912.     // well.  However, I chose this approach because it seems
  913.     // clearer to me from a client perspective.  Casting a ProcPtr
  914.     // to the appropriate C routine type avoids the confusion
  915.     // of the actual prototype of MoreCFMPatchesCallThrough.
  916.     //
  917.     // Also, I may provide a future mechanism to create a call
  918.     // through ProcPtr from the patch island, and thereby avoid
  919.     // the requirement that the MoreCFMPatches remain resident
  920.     // while patches might call MoreCFMPatchesCallThrough.
  921.  
  922. static pascal OSStatus MorePatchTVectorStatic(TVector *tVectorToPatch,
  923.                               TVector *patchTVectorToAdd,
  924.                               OSType  creator,
  925.                               void      *refcon)
  926.     // See comment in interface part.
  927. {
  928.     OSStatus err;
  929.     PatchIsland *patchIsland;
  930.     ItemCount junkPatchIndex;
  931.  
  932.     MoreAssertQ(kPatchIslandHeaderSize == 52);
  933.     MoreAssertQ(kPatchRecordSize == sizeof(PatchRecord));
  934.  
  935.     MoreAssertQ(tVectorToPatch      != nil);
  936.     MoreAssertQ(patchTVectorToAdd != nil);
  937.  
  938.     // Note that, in the most common case (ie the TVector hasn't
  939.     // been patched already), this code is pretty inefficient.  It
  940.     // basically patches the TVector once with a single entry
  941.     // patch island which just contains the original routine, then
  942.     // replaces that adds the new patch to the patch island.  It
  943.     // may would been more efficient to create a two entry patch
  944.     // island in that case.  But I decided that simplicity was
  945.     // more important that efficiency, especially in this kind
  946.     // of code.
  947.         
  948.     err = noErr;
  949.     if ( ! HasTVectorBeenPatched(tVectorToPatch) ) {
  950.         err = CreateNewPatchIsland(tVectorToPatch);
  951.     }
  952.     if (err == noErr) {
  953.         patchIsland = GetPatchIslandFromTVector(tVectorToPatch);
  954.         err = FindPatchInPatchIsland(patchIsland, patchTVectorToAdd, &junkPatchIndex);
  955.         if (err == noErr) {
  956.             err = kTVectorAlreadyPatchedByYouErr;
  957.         } else if (err == kPatchNotFoundInPatchIslandErr) {
  958.             err = AddPatchToPatchIsland(patchIsland, patchTVectorToAdd,
  959.                                         creator, refcon);
  960.         } else {
  961.             // Unexpected result from FindPatchInPatchIsland.  Need
  962.             // to reanalyse this result checking to see whether it still
  963.             // makes sense.
  964.             MoreAssertQ(false);
  965.         }
  966.     }
  967.     return err;
  968. }
  969.  
  970. static pascal OSStatus MoreUnpatchTVectorStatic(TVector *tVectorToUnpatch, TVector *patchTVectorToRemove)
  971.     // See comment in interface part.
  972. {
  973.     OSStatus err;
  974.     OSStatus junk;
  975.     PatchIsland *patchIsland;
  976.     ItemCount patchIndex;
  977.     ItemCount patchCount;
  978.  
  979.     MoreAssertQ(tVectorToUnpatch     != nil);
  980.     MoreAssertQ(patchTVectorToRemove != nil);
  981.  
  982.     // Like MorePatchTVector, this could be done more efficiently
  983.     // by recognising that a removing a patch from a two entry
  984.     // patch island is equivalent to disposing the patch island
  985.     // itself.  But again I chose the simplest approach.
  986.  
  987.     if ( HasTVectorBeenPatched(tVectorToUnpatch) ) {
  988.         patchIsland = GetPatchIslandFromTVector(tVectorToUnpatch);
  989.         err = FindPatchInPatchIsland(patchIsland, patchTVectorToRemove, &patchIndex);
  990.         if (err == noErr) {
  991.             err = RemovePatchFromPatchIsland(patchIsland, patchIndex);
  992.         }
  993.         if (err == noErr) {
  994.  
  995.             // As RemovePatchFromPatchIsland changes tVectorToUnpatch->codePointer
  996.             // from which patchIsland is derived, we have to get patchIsland
  997.             // again.
  998.  
  999.             patchIsland = GetPatchIslandFromTVector(tVectorToUnpatch);
  1000.  
  1001.             junk = GetPatchIslandPatchCount(patchIsland, &patchCount);
  1002.             MoreAssertQ(junk == noErr);
  1003.             if (junk == noErr && patchCount == 1) {
  1004.                 DestroyPatchIsland(patchIsland);
  1005.             }
  1006.         }
  1007.     } else {
  1008.         err = kVectorNotPatchedByUsErr;
  1009.     }
  1010.     return err;
  1011. }
  1012.  
  1013. static pascal OSStatus MoreCountPatchesStatic(TVector *tVector, ItemCount *count)
  1014.     // See interface comment for MoreCountPatches.
  1015. {
  1016.     OSStatus err;
  1017.     PatchIsland *patchIsland;
  1018.     
  1019.     MoreAssertQ(tVector != nil);
  1020.     MoreAssertQ(count   != nil);
  1021.     
  1022.     if ( HasTVectorBeenPatched(tVector) ) {
  1023.         patchIsland = GetPatchIslandFromTVector(tVector);
  1024.         err = GetPatchIslandPatchCount(patchIsland, count);
  1025.         if (err == noErr) {
  1026.  
  1027.             // Decrement count by one because GetPatchIslandPatchCount
  1028.             // returns the number of patch records in the patch island,
  1029.             // which includes the last patch record, which represents
  1030.             // the original routine.  Clients of this routine won't expect
  1031.             // to see this patch record because they didn't apply the
  1032.             // patch so there's no reason for it to be returned to them.
  1033.             // It's existance is an implementation detail.
  1034.             
  1035.             // Also, assert that count is 2 or more.  This is
  1036.             // because the patch island must always contain: 1) a
  1037.             // least one patch record applied by a client, and
  1038.             // 2) the last patch record that represents the original
  1039.             // routine.  If the patch island contained only
  1040.             // one patch, we would have destroyed it in 
  1041.             // MoreUnpatchTVector.
  1042.             
  1043.             MoreAssertQ(*count > 1);
  1044.             *count -= 1;
  1045.         }
  1046.     } else {
  1047.         err = kVectorNotPatchedByUsErr;
  1048.     }
  1049.  
  1050.     return err;
  1051. }
  1052.  
  1053. static pascal OSStatus MoreGetIndexedPatchInfoStatic(TVector *tVector, ItemCount index,
  1054.                             OSType infoKind, void *buffer, ByteCount bufferSize)
  1055.     // See interface comment for MoreGetIndexedPatchInfo.
  1056. {
  1057.     OSStatus err;
  1058.     PatchIsland *patchIsland;
  1059.     ItemCount patchCount;
  1060.     void *infoSource;
  1061.     ByteCount infoSize;
  1062.     
  1063.     MoreAssertQ(tVector   != nil);
  1064.     MoreAssertQ(index     != 0);
  1065.     MoreAssertQ(buffer != nil);
  1066.  
  1067.     if ( HasTVectorBeenPatched(tVector) ) {
  1068.         patchIsland = GetPatchIslandFromTVector(tVector);
  1069.         err = GetPatchIslandPatchCount(patchIsland, &patchCount);
  1070.         if (err == noErr && (index < 1 || index > patchCount)) {
  1071.             err = kPatchNotFoundErr;
  1072.         }
  1073.         if (err == noErr) {
  1074.         
  1075.             // Compensate for original routine's patch record
  1076.             // at the end of the patch island.  See comments in
  1077.             // MoreCountPatchesStatic for why we do this.
  1078.             
  1079.             MoreAssertQ(patchCount > 1);
  1080.             patchCount -= 1;
  1081.         
  1082.             // Compensate for the zero-based array versus the one-based index.
  1083.             
  1084.             index -= 1;
  1085.             
  1086.             switch (infoKind) {
  1087.                 case kPatchInfoCreator:
  1088.                     infoSource = &patchIsland->patches[index].patchCreator;
  1089.                     infoSize = sizeof(OSType);
  1090.                     break;
  1091.                 case kPatchInfoTVector:
  1092.                     infoSource = &patchIsland->patches[index].patchTVector;
  1093.                     infoSize = sizeof(TVector *);
  1094.                     break;
  1095.                 case kPatchInfoRefcon:
  1096.                     infoSource = &patchIsland->patches[index].patchRefcon;
  1097.                     infoSize = sizeof(void *);
  1098.                     break;
  1099.                 default:
  1100.                     err = paramErr;
  1101.                     break;
  1102.             }
  1103.         }
  1104.         if (err == noErr) {
  1105.             if (infoSize > bufferSize) {
  1106.                 
  1107.                 // The buffer isn't big enough for the data,
  1108.                 // let the caller know about it and copy in
  1109.                 // as much data as possible.
  1110.                 
  1111.                 infoSize = bufferSize;
  1112.                 err = kPatchInfoOverrunErr;
  1113.             }
  1114.             BlockMoveData(infoSource, buffer, infoSize);
  1115.         }
  1116.     } else {
  1117.         err = kVectorNotPatchedByUsErr;
  1118.     }
  1119.  
  1120.     return err;
  1121. }
  1122.  
  1123. ////////////////////////////////////////////////////////////////
  1124. #pragma mark ----- Dynamic Stubs -----
  1125.  
  1126. extern pascal OSStatus MorePatchTVectorDynamic(TVector *tVectorToPatch,
  1127.                             TVector *patchTVectorToAdd,
  1128.                             OSType  creator,
  1129.                             void    *refcon);
  1130. extern pascal OSStatus MoreUnpatchTVectorDynamic(TVector *tVectorToUnpatch,
  1131.                             TVector *patchTVectorToRemove);
  1132. extern pascal OSStatus MoreCountPatchesDynamic(TVector *tVector, ItemCount *count);
  1133. extern pascal OSStatus MoreGetIndexedPatchInfoDynamic(TVector *tVector, ItemCount index,
  1134.                             OSType infoKind, void *buffer, ByteCount bufferSize);
  1135.  
  1136. ////////////////////////////////////////////////////////////////
  1137. #pragma mark ----- API Entry Point Dispatcher -----
  1138.  
  1139. extern pascal OSStatus MorePatchTVector(TVector *tVectorToPatch,
  1140.                             TVector *patchTVectorToAdd,
  1141.                             OSType  creator,
  1142.                             void    *refcon)
  1143.     // See comment in interface part.
  1144. {
  1145.     if (MorePatchTVectorDynamic == (void *) kUnresolvedCFragSymbolAddress) {
  1146.         return MorePatchTVectorStatic(tVectorToPatch, patchTVectorToAdd, creator, refcon);
  1147.     } else {
  1148.         return MorePatchTVectorDynamic(tVectorToPatch, patchTVectorToAdd, creator, refcon);
  1149.     }
  1150. }
  1151.  
  1152. extern pascal OSStatus MoreUnpatchTVector(TVector *tVectorToUnpatch,
  1153.                             TVector *patchTVectorToRemove)
  1154.     // See comment in interface part.
  1155. {
  1156.     if (MoreUnpatchTVectorDynamic == (void *) kUnresolvedCFragSymbolAddress) {
  1157.         return MoreUnpatchTVectorStatic(tVectorToUnpatch, patchTVectorToRemove);
  1158.     } else {
  1159.         return MoreUnpatchTVectorDynamic(tVectorToUnpatch, patchTVectorToRemove);
  1160.     }
  1161. }
  1162.  
  1163. extern pascal OSStatus MoreCountPatches(TVector *tVector, ItemCount *count)
  1164.     // See comment in interface part.
  1165. {
  1166.     if (MoreCountPatchesDynamic == (void *) kUnresolvedCFragSymbolAddress) {
  1167.         return MoreCountPatchesStatic(tVector, count);
  1168.     } else {
  1169.         return MoreCountPatchesDynamic(tVector, count);
  1170.     }
  1171. }
  1172.     
  1173. extern pascal OSStatus MoreGetIndexedPatchInfo(TVector *tVector, ItemCount index,
  1174.                             OSType infoKind, void *buffer, ByteCount bufferSize)
  1175.     // See comment in interface part.
  1176. {
  1177.     if (MoreGetIndexedPatchInfoDynamic == (void *) kUnresolvedCFragSymbolAddress) {
  1178.         return MoreGetIndexedPatchInfoStatic(tVector, index, infoKind, buffer, bufferSize);
  1179.     } else {
  1180.         return MoreGetIndexedPatchInfoDynamic(tVector, index, infoKind, buffer, bufferSize);
  1181.     }
  1182. }
  1183.